package isp.apps.example.shoppingcart.domain;

import java.lang.RuntimeException;

import java.util.Map;
import java.util.HashMap;

import java.math.BigDecimal;

import java.util.Collection;
import java.util.Iterator;
import java.util.List;

public class SimpleShoppingCart
  implements ShoppingCart
{

  private Map cartMap = new HashMap();
  private TaxCalculator ourTaxCalculator;
  private int totalQuantity = 0;
  private int totalDistinctItems = 0;
  private Integer orderId;

  public SimpleShoppingCart()
  {
  }

  public void setTaxCalculator(TaxCalculator t)
  {
    ourTaxCalculator = t;
  }

  /**
     * @param newQuantity must be >= 1
     */
  public void addItem(Item newItem, int newQuantity)
  {
    if (newQuantity < 1)
      //throw new IllegalArgumentException("newQuantity must be greater than 0");
      return;
    CartItem ci;
    //if item is in map
    if (cartMap.containsKey(newItem.getSku()))
    {
      ci = (CartItem) cartMap.get(newItem.getSku());
      ci.setQuantity(ci.getQuantity() + newQuantity);
    }
    //add item with quantity of newQuantity         
    else
    {
      ci = new CartItem();
      ci.setItem(newItem);
      ci.setQuantity(newQuantity);
      BigDecimal tax = ourTaxCalculator.getTax(newItem.getCost());
      tax = tax.setScale(2, BigDecimal.ROUND_HALF_UP);
      ci.setTax(tax);
      ci.setCost(newItem.getCost());
      cartMap.put(newItem.getSku(), ci);
      totalDistinctItems += 1;
    }
    totalQuantity += newQuantity;
  }

  public void addItem(Item newItem)
  {
    addItem(newItem, 1);
  }

  public int removeItem(Item newItem,
                        int removeQuantity)
  {
    if (newItem == null)
      return 0;
    String sku;
    if (!cartMap.containsKey(sku = newItem.getSku()))
      return 0;
    CartItem ci = (CartItem) cartMap.get(sku);
    int q = ci.getQuantity();
    if (removeQuantity >= q)
      return removeAllOfItem(newItem);
    // new quantity will be >= 1
    ci.setQuantity(q - removeQuantity);
    totalQuantity -= removeQuantity;
    return removeQuantity;
  }

  public int removeItem(Item newItem)
  {
    return removeItem(newItem, 1);
  }

  public int removeAllOfItem(Item newItem)
  {
    String sku;
    if (newItem == null)
      return 0;
    if (!cartMap.containsKey(sku = newItem.getSku()))
      return 0;
    CartItem ci = (CartItem) cartMap.get(sku);
    int q = ci.getQuantity();
    cartMap.remove(sku);
    totalQuantity -= q;
    totalDistinctItems -= 1;
    return q;
  }

  public void emptyCart()
  {
    cartMap.clear();
  }

  public int setItemQuantity(String newSku, int newQuantity)
  {
    CartItem ci = (CartItem) cartMap.get(newSku);
    if (ci == null)
      return 0;
    int oldQ = ci.getQuantity();
    if (newQuantity == 0)
    {
      removeAllOfItem(ci.getItem());
      return 0;
    }
    else
    {
      ci.setQuantity(newQuantity);
      return newQuantity;
    }
  }

  public boolean isEmpty()
  {
    return cartMap.isEmpty();
  }

  public int getItemQuantity(Item newItem)
  {
    if (cartMap.containsKey(newItem.getSku()))
      return ((CartItem) (cartMap.get(newItem.getSku()))).getQuantity();
    return 0;
  }

  public int getCartDistinctItemCount()
  {
    int count = 0;
    Collection c = cartMap.values();
    for (Iterator i = c.iterator(); i.hasNext(); count++)
    {
      i.next();
    }
    return count;
  }

  public int getCartTotalQuantityCount()
  {
    int count = 0;
    Collection c = cartMap.values();
    for (Iterator i = c.iterator(); i.hasNext(); )
    {
      count += ((CartItem) i.next()).getQuantity();
    }
    return count;
  }

  public Item getItemBySku(String sku)
  {
    if (sku == null)
      return null;
    CartItem ci = (CartItem) cartMap.get(sku);
    if (ci != null)
      return ci.getItem();
    return null;
  }

  public BigDecimal getTotalPrice()
  {
    BigDecimal totalPrice = getTotalCost();
    totalPrice = totalPrice.add(ourTaxCalculator.getTax(totalPrice));
    return totalPrice.setScale(2, BigDecimal.ROUND_HALF_UP);
  }


  public BigDecimal getTotalTax()
  {
    BigDecimal totalPrice = getTotalCost();
    BigDecimal total = ourTaxCalculator.getTax(totalPrice);
    return total.setScale(2, BigDecimal.ROUND_HALF_UP);
  }

  public BigDecimal getTotalCost()
  {
    CartItem ci;
    BigDecimal cost;
    BigDecimal totalCost = new BigDecimal(0);
    Collection c = cartMap.values();
    for (Iterator i = c.iterator(); i.hasNext(); )
    {
      ci = ((CartItem) i.next());
      cost = ci.getItem().getCost();
      cost = cost.multiply(new BigDecimal(ci.getQuantity()));
      totalCost = totalCost.add(cost);
    }
    return totalCost.setScale(2, BigDecimal.ROUND_HALF_UP);
  }


  public Collection getCartItems()
  {
    return cartMap.values();
  }


  public int removeBySku(String removeSku)
  {
    Item i = getItemBySku(removeSku);
    return removeAllOfItem(i);
  }

  public void setOrderId(Integer orderId)
  {
    this.orderId = orderId;
  }

  public Integer getOrderId()
  {
    return orderId;
  }
}
